package justweb

import (
	"fmt"
	"sort"
	"strings"
)

const (
	// 根节点，只有根用这个
	nodeTypeRoot = iota

	// *
	nodeTypeAny

	// 路径参数
	nodeTypeParam

	// 正则
	nodeTypeReg

	// 静态，即完全匹配
	nodeTypeStatic
)

type treenode struct {
	path       string // 因为这里现在开始可以是 * 、 :param 、 reg ， 所以做不同处理可以增加字段
	ChildNodes []*treenode
	handler    HandlerFunc
	matchChild MatchFunc // 根据path的不同而使用不同的匹配函数,将必要数据写入请求context中
	nodeType   int
	// ...
} // 带有表头的链表，头节点的path不放值

type MatchFunc func(path string, c *Context) bool

// 根据[]string 添加路由树的节点
func (n *treenode) NewChildren(paths []string, f HandlerFunc) (BaseNode, error) {
	nn := n
	for _, p := range paths {
		child := NewNode(p, default_newNode) // 将默认的新建函数作为参数
		mm := child.(*treenode)
		nn.ChildNodes = append(nn.ChildNodes, mm)
		nn = mm
	}
	nn.handler = f
	fmt.Println("注册路由：", paths)
	return nn, nil
}

// 查找当前节点的孩子中是否有命中的
// 查找子结点表示有多个命中，要么是* 要么是:param 或者另外分割出来的哪些 -- 优先级在这里使用
// func (n *treenode) FindChildNode(path string, c *Context) (*treenode, bool) {
func (n *treenode) FindChildNode(path string, c *Context) (BaseNode, bool) {
	candidates := make([]*treenode, 0, 3) // 孩子中出现的候选相关
	// for _, m := range n.ChildNodes {
	for i := 0; i < len(n.ChildNodes); i++ {
		// if m.path != "*" && path == m.path { // 通配符匹配时，优先查找相等的
		if n.ChildNodes[i].matchChild(path, c) { // 执行当前结点自己的逻辑 -- 是否完成匹配
			candidates = append(candidates, n.ChildNodes[i])
		}
	}
	// 迭代结束后，candidates如果有值，表示多个命中
	if len(candidates) <= 0 {
		return nil, false
	}

	// 排序，依据nodeType的优先级
	sort.Slice(candidates, func(i, j int) bool {
		return candidates[i].nodeType < candidates[j].nodeType
	})

	return candidates[len(candidates)-1], true
}

// 查找当前树是否存在命中路由
func (n *treenode) FindRouter(pattern string, c *Context) (HandlerFunc, bool) {
	// 两种推进方式，第一是以树为基准往下找；另外一种是以路径为基准，这里采用第二种方式
	paths := strings.Split(strings.Trim(pattern, "/"), "/")
	node := n
	for _, p := range paths {
		if child, ok := node.FindChildNode(p, c); ok {
			m := child.(*treenode)
			c.URLPath += "/" + m.path
			node = m
		} else {
			return nil, false
		}
	}
	// fmt.Println(c.URLPath)

	// 访问目标是/order/detail . 然而我们的树里有/order/detail/first
	// 这样会查找成功，但是并没有处理函数nil，所以返回false
	return node.handler, node.handler != nil
}

// ----------------------------------------------------------------------------

// 这个代码不好扩展
// type options func(*treenode)

// func withPath(path string) options {
// 	return func(n *treenode) {
// 		n.path = path
// 	}
// }

// func withNodeType(t int) options {
// 	return func(n *treenode) {
// 		n.nodeType = t
// 	}
// }
// func withMatch(f MatchFunc) options {
// 	return func(n *treenode) {
// 		n.matchChild = f
// 	}
// }
// func newnode(path string, op ...options) *treenode {
// 	n := &treenode{
// 		path:       path,
// 		ChildNodes: make([]*treenode, 0, 2),
// 		handler:    nil,
// 		matchChild: nil,
// 	}

// 	for _, o := range op {
// 		o(n)
// 	}

// 	return n
// }

// func NewTreeNode(path string) *treenode {
// 	if path == "*" {
// 		return newnode(path, withNodeType(nodeTypeAny),
// 			withMatch(func(path string, c *Context) bool {
// 				return true
// 			}))
// 	} else if strings.HasPrefix(path, ":") {
// 		return newnode(path, withNodeType(nodeTypeParam),
// 			withMatch(func(p string, c *Context) bool {
// 				if c != nil {
// 					c.PathParams[path[1:]] = p // 路径参数传入上下文
// 				}
// 				// 如果自身是一个参数路由
// 				// 然后突然又在这个地方注册一个通配*  就是位置重叠了，命中谁的问题
// 				return p != "*" // 表示不认*
// 			}))
// 	}
// 	return newnode(path, withNodeType(nodeTypeStatic),
// 		withMatch(func(p string, c *Context) bool {
// 			return path == p && p != "*"
// 		}))
// }
